<?php

/**
 * User model.
 *
 * @package    sfDoctrineGuardPlugin
 * @subpackage model
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
 * @version    SVN: $Id: PluginsfGuardUser.class.php 25605 2009-12-18 18:55:55Z Jonathan.Wage $
 */

abstract class PluginsfGuardUser extends BasesfGuardUser
{
  protected
    $_groups         = null,
    $_permissions    = null,
    $_allPermissions = null;

    static $USERNAME = "pseudo";
    static $TABLE = "sfGuardUser";
    static $DEFAULT_GROUP = "player";
    
   /**
   * Returns the string representation of the object: "Full Name (username)"
   *
   * @return string
   */
  public function isWatching($ktd_adventure){
        return KTDAdventureWatch::isWatching($this, $ktd_adventure);
  }
  public function watch(KTDAdventure $ktd_adventure){
      if(!$this->isWatching($ktd_adventure)){
          $w = new KTDAdventureWatch();
          $w->setPlayer($this);
          $w->setAdventure($ktd_adventure);
          $w->save();
      }
  }
  public function unwatch(KTDAdventure $ktd_adventure){
      $q = $this->getWatchQuery();
      $q->andWhere("w.adventure_id = ?", $ktd_adventure->getId());
      $q->delete();
      $q->execute();

  }
  public function getWatchQuery(){
      $q = KTDAdventureWatch::getKTDAdventureWatchQuery();
      $q->where("w.player_id = ?", $this->getId());
      return $q;
  }
  public function getNotificationsQuery(){
      $q = Doctrine_Query::create()->from("KTDNotification n")->
              leftJoin("n.Player pl")->
              where("pl.id = ?", $this->getId());
      return $q;
  }
  public function getOrderedNotifications(){
      $q = $this->getNotificationsQuery()->orderBy("n.created_at DESC");
      return $q->execute();
  }
  public function countNotifications(){
      $q = $this->getNotificationsQuery()->count();
      return $q;
  }
  public function hasEnoughMoney($money){
      if($this->getMoney() < $money)
              return false;
      return true;
  }
  public function giveMoney($money){
      $this->setMoney($this->getMoney() + $money);
  }
  public function removeMoney($money){
      $amount = $this->getMoney() - $money;
      $this->setMoney($amount);

      if($this->getMoney() < 0)
              $this->setMoney(0);
  }
  public static function getPlayerQuery(){
    $q = Doctrine_Query::create();
    $q->from("sfGuardUser u");
    return $q;
  }
  public static function getNumberOfPlayers(){
      $q = PluginsfGuardUser::getPlayerQuery();
      return $q->count();
  }
  public static function getLastPlayer(){
    $q = PluginsfGuardUser::getPlayerQuery();
    $q->orderBy("id DESC");
    return $q->fetchOne();
  }
  //donne l'argent au gars, renvois false si il n'a pas assez d'argent
  public function giveMoneyTo($money, $sfGuardUser){
      if(!$this->hasEnoughMoney($money))
        return false;
      else{
          $sfGuardUser->giveMoney($money);
          $this->removeMoney($money);
          return true;
      }
  }
  public function generateActivationToken(){
      $this->activation_token = md5($this->getUsername().$this->getPassword().rand(111,999));
      return $this->activation_token;
  }
  public function isActivationToken($token){
      return $token == $this->getActivationToken();
  }
  public function isActive(){
      return $this->getIsActive();
  }
  public function countNewPrivateMessage(){
     return KTDPrivateMessage::countNewPrivateMessage($this);
  }
  public function incMsgNb(){
      $this->setMsgCount($this->getMsgCount() + 1);
  }
  public function decMsgNb(){
      $this->setMsgCount($this->getMsgCount() - 1);
  }
  public function getParsedSignature(){
      return KTDCodeParser::getSingleton()->getParsedText($this->getSignature(), true);
  }
  //Retourne si le joueur a un personnage selectionné
  public function hasActualCharacter(){
      if($this->getActualCharacterId() == NULL)
              return false;
      else
          return true;
  }
  public function getUsernameSlug(){
      return KillTheDragon::slugify($this->getUsername());
  }
  public function hasCharacters(){
      return count($this->getKTDCharacters()) == 0 ? false : true;
  }
  public function __toString()
  {
    return (string) $this->getPseudo().' ('.$this->getUsername().')';
  }
  static public function getOnlineUsers(){
     $online_users = Doctrine_Core::getTable('sfGuardUser')->
                        createQuery('a')->
                        where('presence > ?', date('Y-m-d H:i:s', time() - sfConfig::get('app_online_limit')))->
                        execute();
     return $online_users;
  }
  public function isOnline(){
   
      if($this->getPresence()  >  date('Y-m-d H:i:s', time() - sfConfig::get('app_online_limit')))
              return true;
      else
          return false;
   }
  /**
   * Returns the first and last name of the user concatenated together
   *
   * @return string $name
   */
  public function getKTDCharactersByIdPseudo(){
    $array = array();
    foreach($this->getKTDCharacters() as $character)
    {
        $array[$character->getId()] = $character->getPseudo();
    }
    return $array;
  }
  public function doAutocompleteQuery($term){
     $q = Doctrine_Core::getTable('sfGuardUser')->createQuery('s')
             ->where("s.pseudo LIKE :term");
     return $q->execute(array(':term' => '%'.$term.'%'));
  }
  public function getName()
  {
    return trim($this->getFirstName().' '.$this->getLastName());
  }

  /**
   * Sets the user password.
   *
   * @param string $password
   */
  public function setPassword($password)
  {
    if (!$password && 0 == strlen($password))
    {
      return;
    }

    if (!$salt = $this->getSalt())
    {
      $salt = md5(rand(100000, 999999).$this->getUsername());
      $this->setSalt($salt);
    }
    $modified = $this->getModified();
    if ((!$algorithm = $this->getAlgorithm()) || (isset($modified['algorithm']) && $modified['algorithm'] == $this->getTable()->getDefaultValueOf('algorithm')))
    {
      $algorithm = sfConfig::get('app_sf_guard_plugin_algorithm_callable', 'sha1');
    }
    $algorithmAsStr = is_array($algorithm) ? $algorithm[0].'::'.$algorithm[1] : $algorithm;
    if (!is_callable($algorithm))
    {
      throw new sfException(sprintf('The algorithm callable "%s" is not callable.', $algorithmAsStr));
    }
    $this->setAlgorithm($algorithmAsStr);

    $this->_set('password', call_user_func_array($algorithm, array($salt.$password)));
  }

  /**
   * Returns whether or not the given password is valid.
   *
   * @param string $password
   * @return boolean
   */
  public function checkPassword($password)
  {
    if ($callable = sfConfig::get('app_sf_guard_plugin_check_password_callable'))
    {
      return call_user_func_array($callable, array($this->getUsername(), $password, $this));
    }
    else
    {
      return $this->checkPasswordByGuard($password);
    }
  }

  /**
   * Returns whether or not the given password is valid.
   *
   * @param string $password
   * @return boolean
   * @throws sfException
   */
  public function checkPasswordByGuard($password)
  {
    $algorithm = $this->getAlgorithm();
    if (false !== $pos = strpos($algorithm, '::'))
    {
      $algorithm = array(substr($algorithm, 0, $pos), substr($algorithm, $pos + 2));
    }
    if (!is_callable($algorithm))
    {
      throw new sfException(sprintf('The algorithm callable "%s" is not callable.', $algorithm));
    }

    return $this->getPassword() == call_user_func_array($algorithm, array($this->getSalt().$password));
  }

  /**
   * Adds the user a new group from its name.
   *
   * @param string $name The group name
   * @param Doctrine_Connection $con A Doctrine_Connection object
   * @throws sfException
   */
  public function addGroupByName($name, $con = null)
  {
    $group = Doctrine_Core::getTable('sfGuardGroup')->findOneByName($name);
    if (!$group)
    {
      throw new sfException(sprintf('The group "%s" does not exist.', $name));
    }

    $ug = new sfGuardUserGroup();
    $ug->setUser($this);
    $ug->setGroup($group);

    $ug->save($con);
  }

  /**
   * Adds the user a permission from its name.
   *
   * @param string $name The permission name
   * @param Doctrine_Connection $con A Doctrine_Connection object
   * @throws sfException
   */
  public function addPermissionByName($name, $con = null)
  {
    $permission = Doctrine_Core::getTable('sfGuardPermission')->findOneByName($name);
    if (!$permission)
    {
      throw new sfException(sprintf('The permission "%s" does not exist.', $name));
    }

    $up = new sfGuardUserPermission();
    $up->setUser($this);
    $up->setPermission($permission);

    $up->save($con);
  }

  /**
   * Checks whether or not the user belongs to the given group.
   *
   * @param string $name The group name
   * @return boolean
   */
  public function hasGroup($name)
  {
    $this->loadGroupsAndPermissions();
    return isset($this->_groups[$name]);
  }

  /**
   * Returns all related groups names.
   *
   * @return array
   */
  public function getGroupNames()
  {
    $this->loadGroupsAndPermissions();
    return array_keys($this->_groups);
  }

  /**
   * Returns whether or not the user has the given permission.
   *
   * @return boolean
   */
  public function getRandomCharacter(){
      $chars = $this->getKTDCharacters();
      if(count($chars) == 0)
          return NULL;
      $i = rand(0, $chars - 1);
      return $chars[$i];
  }
  public function hasPermission($name)
  {
    $this->loadGroupsAndPermissions();
    if($this->is_super_admin || isset($this->_allPermissions["admin"]))
            return true;
    else
        return isset($this->_allPermissions[$name]);
  }
  //Retourne si l'utilisateur a la permission d'apporter des modifications relatives à un autre utilisateur ($name : permission sans _all)
  public function hasRelPermission($name, $rel_user){
      $this->loadGroupsAndPermissions();
      if($rel_user->getId() == $this->getId())
              return $this->hasPermission($name);
      else
              return $this->hasPermission($name.'_all');
  }

  /**
   * Returns an array of all user's permissions names.
   *
   * @return array
   */
  public function getPermissionNames()
  {
    $this->loadGroupsAndPermissions();
    return array_keys($this->_allPermissions);
  }

  /**
   * Returns an array containing all permissions, including groups permissions
   * and single permissions.
   *
   * @return array
   */
  public function getAllPermissions()
  {
    if (!$this->_allPermissions)
    {
      $this->_allPermissions = array();
      $permissions = $this->getPermissions();
      foreach ($permissions as $permission)
      {
        $this->_allPermissions[$permission->getName()] = $permission;
      }

      foreach ($this->getGroups() as $group)
      {
        foreach ($group->getPermissions() as $permission)
        {
          $this->_allPermissions[$permission->getName()] = $permission;
        }
      }
    }

    return $this->_allPermissions;
  }

  /**
   * Returns an array of all permission names.
   *
   * @return array
   */
  public function getAllPermissionNames()
  {
    return array_keys($this->getAllPermissions());
  }

  /**
   * Loads the user's groups and permissions.
   *
   */
  public function loadGroupsAndPermissions()
  {
    $this->getAllPermissions();
    
    if (!$this->_permissions)
    {
      $permissions = $this->getPermissions();
      foreach ($permissions as $permission)
      {
        $this->_permissions[$permission->getName()] = $permission;
      }
    }
    
    if (!$this->_groups)
    {
      $groups = $this->getGroups();
      foreach ($groups as $group)
      {
        $this->_groups[$group->getName()] = $group;
      }
    }
  }

  /**
   * Reloads the user's groups and permissions.
   */
  public function reloadGroupsAndPermissions()
  {
    $this->_groups         = null;
    $this->_permissions    = null;
    $this->_allPermissions = null;
  }

  /**
   * Sets the password hash.
   *
   * @param string $v
   */
  public function setPasswordHash($v)
  {
    if (!is_null($v) && !is_string($v))
    {
      $v = (string) $v;
    }

    if ($this->password !== $v)
    {
      $this->_set('password', $v);
    }
  }
}
